package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.api.dto.leanring.LearningRecordFormDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.model.po.LearningLesson;
import com.tianji.learning.model.po.LearningRecord;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 学习记录表，服务实现类
 */
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    private final ILearningLessonService lessonService;

    private final CourseClient courseClient;

    /**
     * 查询指定课程的学习记录
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {

        //1.获取当前用户
        Long user = UserContext.getUser();
        //2.查询lesson信息
        LearningLesson learningLesson = lessonService.queryByUserAndCourseId(user, courseId);
        if(learningLesson == null){
            throw new BizIllegalException("该用户未拥有该课程");
        }
        //3.查询record表的小节学习进度
        List<LearningRecord> records = lambdaQuery()
                .eq(LearningRecord::getLessonId, learningLesson.getId())
                .list();
        // 没有得到学习记录不能抛异常
        // if(CollUtils.isEmpty(records)){
        //     return null;
        // }

        //4.设置LearningLessonDTO的信息
        LearningLessonDTO learningLessonDTO = new LearningLessonDTO();

        learningLessonDTO.setId(learningLesson.getId());
        learningLessonDTO.setLatestSectionId(learningLesson.getLatestSectionId());

        //5.复制小节记录集合到LearningRecordDTO
        List<LearningRecordDTO> dtos = BeanUtils.copyList(records, LearningRecordDTO.class);
        learningLessonDTO.setRecords(dtos);

        return learningLessonDTO;

//        Long userId = UserContext.getUser();
//
//        LearningLesson lesson = lessonService.queryByUserAndCourseId(userId, courseId);
//
//        List<LearningRecord> records = this.lambdaQuery()
//                .eq(LearningRecord::getLessonId, lesson.getId())
//                .list();
//
//        LearningLessonDTO learningLessonDTO = new LearningLessonDTO();
//        learningLessonDTO.setId(lesson.getId());
//        learningLessonDTO.setLatestSectionId(lesson.getLatestSectionId());
//        learningLessonDTO.setRecords(BeanUtils.copyList(records, LearningRecordDTO.class));
//
//        return learningLessonDTO;
    }

    /**
     * 提交学习记录
     *
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitLearningRecord(LearningRecordFormDTO dto) {
        //当前用户ID
        Long userId = UserContext.getUser();

        //判断该学员是否拥有该课程
        LearningLesson learningLesson = lessonService.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getId, dto.getLessonId())
                .one();
        if (learningLesson == null || ObjectUtils.equal(learningLesson.getStatus(), LessonStatus.EXPIRED.getValue())) {
            throw new BadRequestException("异常数据");
        }

        //1. 判断本次提交的学习记录是考试还是视频
        Boolean examType = ObjectUtils.equal(SectionType.EXAM, dto.getSectionType());

        //封装LearningRecord
        LearningRecord learningRecord = BeanUtils.copyBean(dto, LearningRecord.class);
        learningRecord.setUserId(userId);//用户id

        if (examType) { //小节类型为考试

            //1.1 添加learning_record
            //封装数据
            learningRecord.setFinished(true);//完成学习
            learningRecord.setCreateTime(dto.getCommitTime());//第一次考试时间
            learningRecord.setFinishTime(dto.getCommitTime());//完成学习的时间

            //更新数据库
            boolean result = this.save(learningRecord);

            if (!result) {
                throw new DbException("添加数据到learning_record失败");
            }
            //更新Learning_lesson表数据
            firstFinish(userId, dto);

            return;
        }

        //小节类型为视频
        //2. 判断视屏是否看过
        LearningRecord learningRecord1 = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, dto.getLessonId())
                .eq(LearningRecord::getSectionId, dto.getSectionId())
                .one();
        if (learningRecord1 == null) {//说明视频没被看过

            //新增learning_record
            //封装数据
            learningRecord.setCreateTime(dto.getCommitTime());//第一次观看时间

            //更新数据库
            boolean result = this.save(learningRecord);

            if (!result) {
                throw new DbException("添加数据到learning_record失败");
            }

            //更新Learning_lesson表数据
            noFirstFinish(userId, dto);

            return;
        }

        //视频被看过修改learning_record的moment
        boolean result1 = this.lambdaUpdate()
                .eq(LearningRecord::getLessonId, dto.getLessonId())
                .eq(LearningRecord::getSectionId, dto.getSectionId())
                .set(LearningRecord::getMoment, dto.getMoment())
                .update();
        if (!result1) {
            throw new DbException("添加数据到learning_record失败");
        }

        //视频被看过

        //判断视频是否看完
        Boolean finishResult = dto.getDuration() - dto.getMoment() < dto.getMoment();//看完为true
        if (!finishResult || (finishResult && learningRecord1.getFinished())) { //没看完或者不是第一次看完
            noFirstFinish(userId, dto);

            return;
        }

        //到这说明视频被看过并且这是第一次看完
        //修改learning_record的finished和finish_time
        boolean result2 = this.lambdaUpdate()
                .eq(LearningRecord::getLessonId, dto.getLessonId())
                .eq(LearningRecord::getSectionId, dto.getSectionId())
                .set(LearningRecord::getFinished, finishResult)
                .set(LearningRecord::getFinishTime, dto.getCommitTime())
                .update();
        if (!result2) {
            throw new DbException("添加数据到learning_record失败");
        }

        firstFinish(userId, dto);
    }

    /**
     * 当有学习记录提交且是第一次学完or看完时更新Learning_lesson表数据
     *
     * @param userId 用户ID
     * @param dto
     */

    private void firstFinish(Long userId, LearningRecordFormDTO dto) {

        //获取Learning_lesson表中LessonId对应的原始数据
        LearningLesson learningLesson = lessonService.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getId, dto.getLessonId())
                .one();

        //调用远程接口获取当前课程的相关数据
        CourseFullInfoDTO courseFullInfoDTO = courseClient.getCourseInfoById(learningLesson.getCourseId(), false, false);

        //已学习小节数量
        Integer learnedSections = learningLesson.getLearnedSections() + 1;

        //已学习小节数量与课程总节数是否相等
        boolean statusResult = courseFullInfoDTO.getSectionNum() <= learnedSections;

        //构造更新条件
        LambdaUpdateWrapper<LearningLesson> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(LearningLesson::getId, dto.getLessonId());//课表ID
        wrapper.eq(LearningLesson::getUserId, userId);//用户ID
        wrapper.setSql("learned_sections = learned_sections + 1");//设置已学习小数量
        wrapper.set(ObjectUtils.equal(learningLesson.getStatus(), LessonStatus.NOT_BEGIN.getValue()), LearningLesson::getStatus, LessonStatus.LEARNING.getValue());//设置课程状态为学习中
        wrapper.set(statusResult, LearningLesson::getStatus, LessonStatus.FINISHED.getValue());//设置课程是否学完
        wrapper.set(LearningLesson::getLatestSectionId, dto.getSectionId());//最近一次学习的小节id
        wrapper.set(LearningLesson::getLatestLearnTime, dto.getCommitTime());//设置最近一次学习的时间

        //跟新数据库
        boolean result = lessonService.update(wrapper);
        if (!result) {
            throw new DbException("提交学习记录失败");
        }
    }

    /**
     * 当有学习记录提交且不是第一次看完时更新Learning_lesson表数据
     *
     * @param userId 用户ID
     * @param dto
     */

    private void noFirstFinish(Long userId, LearningRecordFormDTO dto) {

        //获取Learning_lesson表中LessonId对应的原始数据
        LearningLesson learningLesson = lessonService.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getId, dto.getLessonId())
                .one();

        //构造更新条件
        LambdaUpdateWrapper<LearningLesson> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(LearningLesson::getId, dto.getLessonId());//课表ID
        wrapper.eq(LearningLesson::getUserId, userId);//用户ID
        wrapper.set(ObjectUtils.equal(learningLesson.getStatus(), LessonStatus.NOT_BEGIN.getValue()), LearningLesson::getStatus, LessonStatus.LEARNING.getValue());//设置课程状态为学习中
        wrapper.set(LearningLesson::getLatestSectionId, dto.getSectionId());//最近一次学习的小节id
        wrapper.set(LearningLesson::getLatestLearnTime, dto.getCommitTime());//设置最近一次学习的时间

        //更新数据库
        boolean result = lessonService.update(wrapper);
        if (!result) {
            throw new DbException("提交学习记录失败");
        }
    }
}